﻿using System.Linq;
using System.Reflection;
using D.Util.UtilIoc;
using D.Util.UtilMiniProfiler;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;

namespace D.UtilSqlsugarOrm
{
    public static class SqlSugarOrm
    {
        /// <summary>
        /// Sqlsugar 上下文初始化
        /// </summary>
        /// <param name="services"></param>
        public static void AddSqlSugar(this IServiceCollection services, DbConfig dbConfig)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));

            if (dbConfig.IsCreateDb)
            {
                // 初始化数据库表结构及种子数据
                InitDatabase(dbConfig);
            }

            // 配置
            var config = new ConnectionConfig()
            {
                ConnectionString = dbConfig.ConnectionString,
                DbType = GetDbType(dbConfig.DbType),
            };
            // 把多个连接对象注入服务，SqlSugarScope用AddSingleton单例
            SqlSugarScope sqlSugar = new SqlSugarScope(config);

            var res = sqlSugar.Ado.IsValidConnection();
            if (res)
            {
                Console.WriteLine("数据库连接成功");
            }
            else
            {
                Console.WriteLine("数据库连接失败");
            }

            services.AddSingleton<ISqlSugarClient>(sqlSugar); // 单例注册
                                                              //services.AddScoped(typeof(SqlSugarRepository<>)); // 仓储注册
                                                              //services.AddUnitOfWork<SqlSugarUnitOfWork>(); // 事务与工作单元注册
                                                              //services.AddScoped(typeof(BaseRepository<>)); // 仓储注册

            // 监听sql
#if DEBUG
            SetDbAop(sqlSugar);
#endif
        }

        /// <summary>
        /// 配置Aop
        /// </summary>
        /// <param name="db"></param>
        public static void SetDbAop(SqlSugarScope db)
        {
            var config = db.CurrentConnectionConfig;

            // 设置超时时间
            db.Ado.CommandTimeOut = 30;
            db.Aop.OnLogExecuted = (sql, pars) =>
            {
                Console.WriteLine("SqlSugar", "Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
            };
            // 打印SQL语句
            db.Aop.OnLogExecuting = (sql, pars) =>
            {
                var originColor = Console.ForegroundColor;
                if (sql.StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                    Console.ForegroundColor = ConsoleColor.Green;
                if (sql.StartsWith("UPDATE", StringComparison.OrdinalIgnoreCase) || sql.StartsWith("INSERT", StringComparison.OrdinalIgnoreCase))
                    Console.ForegroundColor = ConsoleColor.Yellow;
                if (sql.StartsWith("DELETE", StringComparison.OrdinalIgnoreCase))
                    Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("【" + DateTime.Now + "——执行SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, sql, pars) + "\r\n");
                Console.ForegroundColor = originColor;
#if DEBUG
                MiniProfilerUtil.PrintToMiniProfiler("SqlSugar-Info", sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value)));
#endif
            };
            db.Aop.OnError = (ex) =>
            {
                if (ex.Parametres == null) return;
                var originColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.DarkRed;
                var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
                Console.WriteLine("【" + DateTime.Now + "——错误SQL】\r\n" + UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres) + "\r\n");
                Console.ForegroundColor = originColor;

#if DEBUG
                MiniProfilerUtil.PrintToMiniProfiler("SqlSugar-Error", $"{ex.Message}{Environment.NewLine}{ex.Sql}{pars}{Environment.NewLine}");
#endif
            };

            //// 数据审计
            //db.Aop.DataExecuting = (oldValue, entityInfo) =>
            //{
            //    if (entityInfo.OperationType == DataFilterType.InsertByObject)
            //    {
            //        // 主键(long类型)且没有值的---赋值雪花Id
            //        if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long))
            //        {
            //            var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
            //            if (id == null || (long)id == 0)
            //                entityInfo.SetValue(YitIdHelper.NextId());
            //        }
            //        if (entityInfo.PropertyName == "CreateTime")
            //            entityInfo.SetValue(DateTime.Now);

            //    }
            //    if (entityInfo.OperationType == DataFilterType.UpdateByObject)
            //    {
            //        if (entityInfo.PropertyName == "UpdateTime")
            //            entityInfo.SetValue(DateTime.Now);
            //    }
            //};
        }

        /// <summary>
        /// 初始化数据库
        /// </summary>
        /// <param name="db"></param>
        /// <param name="dbConfig"></param>
        private static void InitDatabase(DbConfig dbConfig)
        {
            SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
            {
                ConnectionString = dbConfig.CreateDbConn,
                DbType = GetDbType(dbConfig.DbType),
            });

            // 1. 创建数据库
            var dbtype = GetDbType(dbConfig.DbType);
            if (dbtype != DbType.Oracle) // Oracle和个别国产库需不支持该方法，需要手动建库
                sqlSugar.DbMaintenance.CreateDatabase();

            // 2. 获取所有实体表,批量创建表
            var assemblies = RuntimeHelper.GetAllAssemblies().ToList();
            assemblies.ForEach(assembly =>
            {
                Type[] types = assembly.GetTypes().Where(m => !m.IsInterface && !m.IsAbstract && m.IsClass && m.IsDefined(typeof(SugarTable))).ToArray();
                if (types.Count() > 0)
                {
                    // 根据types创建表
                    sqlSugar.CodeFirst.SetStringDefaultLength(200).InitTables(types);
                }
            });
        }

        public static DbType GetDbType(int dataType)
        {
            if (dataType == 0)
            {
                return DbType.MySql;
            }
            else if (dataType == 1)
            {
                return DbType.SqlServer;
            }
            else if (dataType == 2)
            {
                return DbType.Sqlite;
            }
            else if (dataType == 3)
            {
                return DbType.Oracle;
            }
            else if (dataType == 4)
            {
                return DbType.PostgreSQL;
            }
            else if (dataType == 5)
            {
                return DbType.Dm;
            }
            else if (dataType == 6)
            {
                return DbType.Kdbndp;
            }
            else if (dataType == 7)
            {
                return DbType.Oscar;
            }
            //else if (dataType == 8)
            //{
            //    return DbType.MySqlConnector;
            //}
            else if (dataType == 9)
            {
                return DbType.Access;
            }
            else if (dataType == 10)
            {
                return DbType.OpenGauss;
            }
            else if (dataType == 11)
            {
                return DbType.QuestDB;
            }
            else if (dataType == 12)
            {
                return DbType.HG;
            }
            else if (dataType == 13)
            {
                return DbType.ClickHouse;
            }
            else if (dataType == 14)
            {
                return DbType.GBase;
            }
            else if (dataType == 15)
            {
                return DbType.Odbc;
            }
            return 0;
        }
    }
}